/******************************************************************************\
 * Filename   : bwenc_venc.c
 * Copyright  : 
 * Created    : 2018-10-31 by litao
 * Description:
 * 
\******************************************************************************/
#include "enc_venc.h"

/******************************************************************************
* funciton : Start venc stream mode (h264, mjpeg)
* note      : rate control parameter need adjust, according your case.
******************************************************************************/
HI_S32 enc_venc_start(HI_S32 chan_num, stENC_VIDSET *p_videoSet)
{
    HI_S32 s32Ret;
    VENC_CHN_ATTR_S stVencChnAttr;
	
    VENC_ATTR_H264_S stH264Attr;
    VENC_ATTR_H264_CBR_S    stH264Cbr;
    VENC_ATTR_H264_VBR_S    stH264Vbr;
	VENC_ATTR_H264_AVBR_S    stH264AVbr;
    VENC_ATTR_H264_FIXQP_S  stH264FixQp;
	
    VENC_ATTR_H265_S        stH265Attr;
    VENC_ATTR_H265_CBR_S    stH265Cbr;
    VENC_ATTR_H265_VBR_S    stH265Vbr;
    VENC_ATTR_H265_AVBR_S    stH265AVbr;
    VENC_ATTR_H265_FIXQP_S  stH265FixQp;
	
    //VENC_ATTR_MJPEG_S stMjpegAttr;
    //VENC_ATTR_MJPEG_FIXQP_S stMjpegeFixQp;
    //VENC_ATTR_JPEG_S stJpegAttr;

	VENC_CHN VencChn = chan_num;
	
    SIZE_S stPicSize = {p_videoSet->vid_width, p_videoSet->vid_height};
	PAYLOAD_TYPE_E enType = p_videoSet->vid_codec==1 ? PT_H264 : PT_H265;
	enc_rc_e enRcMode = (enc_rc_e)p_videoSet->vid_rctype;
	HI_U32  u32Profile = (HI_U32)p_videoSet->vid_profile-1;

	printf("width %d height %d enType %d mode %d profile %d\n",
		p_videoSet->vid_width, p_videoSet->vid_height, enType, enRcMode, u32Profile);

    /******************************************
     step 1:  Create Venc Channel    
     ******************************************/
    stVencChnAttr.stVeAttr.enType = enType;
    switch (enType)
    {
        case PT_H264:
        {
            stH264Attr.u32MaxPicWidth = stPicSize.u32Width;
            stH264Attr.u32MaxPicHeight = stPicSize.u32Height;
            stH264Attr.u32PicWidth = stPicSize.u32Width;/*the picture width*/
            stH264Attr.u32PicHeight = stPicSize.u32Height;/*the picture height*/            
            stH264Attr.u32BufSize  = stPicSize.u32Width * stPicSize.u32Height * 2;/*stream buffer size*/
            stH264Attr.u32Profile  = u32Profile;/*0: baseline; 1:MP; 2:HP;  3:svc_t */
            stH264Attr.bByFrame = HI_TRUE;/*get stream mode is slice mode or frame mode?*/
            //stH264Attr.u32BFrameNum = 0;/* 0: not support B frame; >=1: number of B frames */
            //stH264Attr.u32RefNum = 1;/* 0: default; number of refrence frame*/
            memcpy(&stVencChnAttr.stVeAttr.stAttrH264e, &stH264Attr, sizeof(VENC_ATTR_H264_S));
            if (ENC_RC_CBR == enRcMode)
            {
                stVencChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
                stH264Cbr.u32Gop         = p_videoSet->vid_gopsize;
                stH264Cbr.u32StatTime    = 1; /* stream rate statics time(s) */
                stH264Cbr.u32SrcFrmRate  = p_videoSet->vid_fpsden; /* input (vi) frame rate */
                stH264Cbr.fr32DstFrmRate = p_videoSet->vid_fpsden; /* target frame rate */
                stH264Cbr.u32BitRate = p_videoSet->vid_bitrate_kb; /* average bit rate */
                stH264Cbr.u32FluctuateLevel = 1; /* average bit rate */
				
                memcpy(&stVencChnAttr.stRcAttr.stAttrH264Cbr, &stH264Cbr, sizeof(VENC_ATTR_H264_CBR_S));
            }
            else if (ENC_RC_FIXQP == enRcMode)
            {
                stVencChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264FIXQP;
                stH264FixQp.u32Gop         = p_videoSet->vid_gopsize;
                stH264FixQp.u32SrcFrmRate  = p_videoSet->vid_fpsden;
                stH264FixQp.fr32DstFrmRate = p_videoSet->vid_fpsden;
                stH264FixQp.u32IQp = 20;
                stH264FixQp.u32PQp = 23;
                stH264FixQp.u32BQp = 23;
				
                memcpy(&stVencChnAttr.stRcAttr.stAttrH264FixQp, &stH264FixQp, sizeof(VENC_ATTR_H264_FIXQP_S));
            }
            else if (ENC_RC_VBR == enRcMode)
            {
                stVencChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264VBR;
                stH264Vbr.u32Gop         = p_videoSet->vid_gopsize;
                stH264Vbr.u32StatTime    = 1; /* stream rate statics time(s) */
                stH264Vbr.u32SrcFrmRate  = p_videoSet->vid_fpsden; /* input (vi) frame rate */
                stH264Vbr.fr32DstFrmRate = p_videoSet->vid_fpsden; /* target frame rate */
                stH264Vbr.u32MinQp = 10;
                stH264Vbr.u32MinIQp= 10;
                stH264Vbr.u32MaxQp = 40;
				stH264Vbr.u32MaxBitRate = p_videoSet->vid_bitrate_kb; /* average bit rate */

                memcpy(&stVencChnAttr.stRcAttr.stAttrH264Vbr, &stH264Vbr, sizeof(VENC_ATTR_H264_VBR_S));
            }
            else if (ENC_RC_AVBR == enRcMode)
            {
                stVencChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264AVBR;
                stH264AVbr.u32Gop         = p_videoSet->vid_gopsize;
                stH264AVbr.u32StatTime    = 1; /* stream rate statics time(s) */
                stH264AVbr.u32SrcFrmRate  = p_videoSet->vid_fpsden; /* input (vi) frame rate */
                stH264AVbr.fr32DstFrmRate = p_videoSet->vid_fpsden; /* target frame rate */
				stH264AVbr.u32MaxBitRate = p_videoSet->vid_bitrate_kb; /* average bit rate */

                memcpy(&stVencChnAttr.stRcAttr.stAttrH264AVbr, &stH264AVbr, sizeof(VENC_ATTR_H264_AVBR_S));
            }			
            else
            {
                return HI_FAILURE;
            }
        }
        break;
		
        case PT_H265:
        {
            stH265Attr.u32MaxPicWidth = stPicSize.u32Width;
            stH265Attr.u32MaxPicHeight = stPicSize.u32Height;
            stH265Attr.u32PicWidth = stPicSize.u32Width;/*the picture width*/
            stH265Attr.u32PicHeight = stPicSize.u32Height;/*the picture height*/
            stH265Attr.u32BufSize  = stPicSize.u32Width * stPicSize.u32Height * 2;/*stream buffer size*/
            if (u32Profile >= 1)
            { 
			    stH265Attr.u32Profile = 0; 
			}/*0:MP; */
            else            
			{ 
			    stH265Attr.u32Profile  = u32Profile; 
			}/*0:MP*/
            stH265Attr.bByFrame = HI_TRUE;/*get stream mode is slice mode or frame mode?*/
            memcpy(&stVencChnAttr.stVeAttr.stAttrH265e, &stH265Attr, sizeof(VENC_ATTR_H265_S));
            if (ENC_RC_CBR == enRcMode)
            {
                stVencChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_H265CBR;
                stH265Cbr.u32Gop         = p_videoSet->vid_gopsize;
                stH265Cbr.u32StatTime    = 1; /* stream rate statics time(s) */
                stH265Cbr.u32SrcFrmRate  = p_videoSet->vid_fpsden; /* input (vi) frame rate */
                stH265Cbr.fr32DstFrmRate = p_videoSet->vid_fpsden; /* target frame rate */
                stH265Cbr.u32BitRate = p_videoSet->vid_bitrate_kb; /* average bit rate */
                stH265Cbr.u32FluctuateLevel = 1; /* average bit rate */
				
                memcpy(&stVencChnAttr.stRcAttr.stAttrH265Cbr, &stH265Cbr, sizeof(VENC_ATTR_H265_CBR_S));
            }
            else if (ENC_RC_FIXQP == enRcMode)
            {
                stVencChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_H265FIXQP;

                stH265FixQp.u32Gop         = p_videoSet->vid_gopsize;
                stH265FixQp.u32SrcFrmRate  = p_videoSet->vid_fpsden;
                stH265FixQp.fr32DstFrmRate = p_videoSet->vid_fpsden;
                stH265FixQp.u32IQp = 20;
                stH265FixQp.u32PQp = 23;
                stH265FixQp.u32BQp = 23;
				
                memcpy(&stVencChnAttr.stRcAttr.stAttrH265FixQp, &stH265FixQp, sizeof(VENC_ATTR_H265_FIXQP_S));
            }
            else if (ENC_RC_VBR == enRcMode)
            {
                stVencChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_H265VBR;

                stH265Vbr.u32Gop         = p_videoSet->vid_gopsize;
                stH265Vbr.u32StatTime    = 1; /* stream rate statics time(s) */
                stH265Vbr.u32SrcFrmRate  = p_videoSet->vid_fpsden; /* input (vi) frame rate */
                stH265Vbr.fr32DstFrmRate = p_videoSet->vid_fpsden; /* target frame rate */
                stH265Vbr.u32MinQp = 10;
                stH265Vbr.u32MinIQp= 10;
                stH265Vbr.u32MaxQp = 40;
				stH265Vbr.u32MaxBitRate = p_videoSet->vid_bitrate_kb; /* average bit rate */
				
                memcpy(&stVencChnAttr.stRcAttr.stAttrH265Vbr, &stH265Vbr, sizeof(VENC_ATTR_H265_VBR_S));
            }
			else if (ENC_RC_AVBR == enRcMode)
            {
                stVencChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_H265AVBR;

                stH265AVbr.u32Gop         = p_videoSet->vid_gopsize;
                stH265AVbr.u32StatTime    = 1; /* stream rate statics time(s) */
                stH265AVbr.u32SrcFrmRate  = p_videoSet->vid_fpsden; /* input (vi) frame rate */
                stH265AVbr.fr32DstFrmRate = p_videoSet->vid_fpsden; /* target frame rate */
				stH265AVbr.u32MaxBitRate = p_videoSet->vid_bitrate_kb; /* average bit rate */	
				
                memcpy(&stVencChnAttr.stRcAttr.stAttrH264AVbr, &stH265AVbr, sizeof(VENC_ATTR_H265_AVBR_S));
            }	
            else
            {
                return HI_FAILURE;
            }
        }
        break;	
		
        default:
            return HI_ERR_VENC_NOT_SUPPORT;
    }
	
    stVencChnAttr.stGopAttr.enGopMode  = VENC_GOPMODE_NORMALP;
    stVencChnAttr.stGopAttr.stNormalP.s32IPQpDelta = 0;
    s32Ret = HI_MPI_VENC_CreateChn(VencChn, &stVencChnAttr);
    if (HI_SUCCESS != s32Ret)
    {
        enc_err("HI_MPI_VENC_CreateChn [%d] faild with %#x!\n", VencChn, s32Ret);
        return s32Ret;
    }    
	
    s32Ret = HI_MPI_VENC_StartRecvPic(VencChn);
    if (HI_SUCCESS != s32Ret)
    {
        enc_err("HI_MPI_VENC_StartRecvPic faild with%#x! \n", s32Ret);
        return HI_FAILURE;
    }
	
    return HI_SUCCESS;
}

/******************************************************************************
* funciton : Stop venc ( stream mode -- H264, MJPEG )
******************************************************************************/
HI_S32 enc_venc_stop(HI_S32 chan_num)
{
    HI_S32 s32Ret;
	VENC_CHN VencChn = chan_num;
    /******************************************
     step 1:  Stop Recv Pictures
    ******************************************/
    s32Ret = HI_MPI_VENC_StopRecvPic(VencChn);
    if (HI_SUCCESS != s32Ret)
    {
        enc_err("HI_MPI_VENC_StopRecvPic vechn[%d] failed with %#x!\n", \
                   VencChn, s32Ret);
        return HI_FAILURE;
    }    /******************************************
     step 2:  Distroy Venc Channel
    ******************************************/
    s32Ret = HI_MPI_VENC_DestroyChn(VencChn);
    if (HI_SUCCESS != s32Ret)
    {
        enc_err("HI_MPI_VENC_DestroyChn vechn[%d] failed with %#x!\n", \
                   VencChn, s32Ret);
        return HI_FAILURE;
    }
    return HI_SUCCESS;
}

/******************************************************************************
* function : venc bind vpss
******************************************************************************/
HI_S32 enc_venc_BindVpss(HI_S32 chan_num)
{
    HI_S32 s32Ret = HI_SUCCESS;
    MPP_CHN_S stSrcChn;
    MPP_CHN_S stDestChn;
	VENC_CHN VeChn = chan_num;
	VPSS_GRP VpssGrp = chan_num;
	VPSS_CHN VpssChn = 0;

    stSrcChn.enModId = HI_ID_VPSS;
    stSrcChn.s32DevId = VpssGrp;
    stSrcChn.s32ChnId = VpssChn;
	
    stDestChn.enModId = HI_ID_VENC;
    stDestChn.s32DevId = 0;
    stDestChn.s32ChnId = VeChn;

	printf("vencchan %d vpssgroup %d\n", VeChn, VpssGrp);
	
    s32Ret = HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);
    if (s32Ret != HI_SUCCESS)
    {
        enc_err("failed with %#x!\n", s32Ret);
        return HI_FAILURE;
    }
	
    return s32Ret;
}

/******************************************************************************
* function : venc unbind vpss
******************************************************************************/
HI_S32 enc_venc_UnBindVpss(HI_S32 chan_num)
{
    HI_S32 s32Ret = HI_SUCCESS;
    MPP_CHN_S stSrcChn;
    MPP_CHN_S stDestChn;
	VENC_CHN VeChn = chan_num;
	VPSS_GRP VpssGrp = chan_num;
	VPSS_CHN VpssChn = 0;	
    stSrcChn.enModId = HI_ID_VPSS;
    stSrcChn.s32DevId = VpssGrp;
    stSrcChn.s32ChnId = VpssChn;
    stDestChn.enModId = HI_ID_VENC;
    stDestChn.s32DevId = 0;
    stDestChn.s32ChnId = VeChn;
    s32Ret = HI_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
    if (s32Ret != HI_SUCCESS)
    {
        enc_err("failed with %#x!\n", s32Ret);
        return HI_FAILURE;
    }
    return s32Ret;
}

